﻿/*
 * Jonathan
 * Created by: Jonathan Montiverdi
 * Date: 6/13/2012
 * License: http://jonathan.codeplex.com/license
 */
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;

using Awesomium.Core;
using Jonathan.Data;
using Jonathan.DataAccess.Sqlite;
using Monti.Docking;
using Monti.MVVM.Services;

namespace Jonathan.Logic
{
   /// <summary>
   /// View logic and data for a reader view.
   /// </summary>
   public class ReaderViewModel : DockItem, IDataViewerModel
   {
      #region Fields
      
      private IMain m_Main;
      private IOptions m_Options;
      private Link m_CurrentLink;
      
      private string m_Html;
      
      /// <summary>
      /// Event used to notify the item is closing.
      /// </summary>
      public event EventHandler ItemClosing;
      
      /// <summary>
      /// Event used to execute an html change request.
      /// </summary>
      public event HtmlChangeEventHandler HtmlChangeRequested;
      
      #endregion
      
      #region Setup
      
      /// <summary>
      /// Initializes a new reader logic object.
      /// </summary>
      /// <param name="book">The book the reader will open.</param>
      /// <param name="link">Default link to open.</param>
      public ReaderViewModel (Book book, string link = "")
      {
         this.m_CurrentLink = new Link ("About");
         this.Excerpts = new ObservableCollection<Excerpt> ();
         this.Book = book;
         this.Title = book.Name;
         this.BookInfo = new BookInfo (book);
         if (!string.IsNullOrEmpty (link))
            this.Open (link);
         else
         {
            string mainContent;
            string mainContentTitle;
            this.Html = this.BuildHtml (out mainContent, out mainContentTitle);
         }
      }
      
      #endregion
      
      #region Properties

      /// <summary>
      /// Gets the list of current excerpts.
      /// </summary>
      public ObservableCollection<Excerpt> Excerpts { get; private set; }
      
      /// <summary>
      /// Gets the book the reader is using.
      /// </summary>
      [SqliteIgnore]
      public Book Book { get; private set; }
      
      /// <summary>
      /// Gets the book's information.
      /// </summary>
      [SqliteIgnore]
      public BookInfo BookInfo { get; private set; }
      
      /// <summary>
      /// Gets the main application.
      /// </summary>
      [SqliteIgnore]
      public IMain Main { get { return this.m_Main ?? (this.m_Main = ServiceManager.Resolve <IMain> ()); } }
      
      /// <summary>
      /// Gets the options of the application.
      /// </summary>
      [SqliteIgnore]
      public IOptions Options { get { return this.m_Options ?? (this.m_Options = ServiceManager.Resolve <IOptions> ()); } }
      
      /// <summary>
      /// Gets or Sets the html to display in the data viewer.
      /// </summary>
      [SqliteIgnore]
      public string Html
      {
         get { return this.m_Html; }
         set
         {
            if (this.m_Html != value)
            {
               this.m_Html = value;
               if (this.HtmlChangeRequested != null)
                  this.HtmlChangeRequested (new HtmlChangeEventArgs { TagId = "Html", Content = value });
               this.RaisePropertyChanged ("Html");
            }
         }
      }
      
      #endregion
      
      #region Methods
      
      /// <summary>
      /// Gets the list of a global javascript callbacks if any.
      /// </summary>
      public IDictionary <string, JSCallback> GetCallbacks ()
      {
         return null;
      }
      
      /// <summary>
      /// Builds the current Html string for the viewer.
      /// </summary>
      /// <param name="mainContent">The main content html.</param>
      /// <param name="mainContentTitle">The main content title html.</param>
      private string BuildHtml (out string mainContent, out string mainContentTitle)
      {
         var html = new StringBuilder ();
         html.AppendLine ("<html>");
         
         html.AppendLine (Common.GetHtmlHead (this.Book.Name));
         
         html.AppendLine ("<body>");
         
         html.AppendLine ("<div id='header'>");
         html.AppendLine ("</div>");
         
         html.AppendLine ("<div id='contentsTitle' class=\"label label-info\">Contents</div>");
         
         html.AppendLine ("<div id='contentsTree'>");
         html.AppendLine ("<div class='treeview'>");
         html.AppendLine (this.BookInfo.Contents);
         html.AppendLine ("</div>");
         html.AppendLine ("</div>");

         html.AppendLine ("<div id='mainContentTitle' class=\"label label-info\">");
         mainContentTitle = this.BuildMainContentTitle ();
         html.AppendLine (mainContentTitle);
         html.AppendLine ("</div>");
         
         html.AppendLine ("<div id='mainContent'>");
         mainContent = this.BuildMainContent ();
         html.AppendLine (mainContent);
         html.AppendLine ("</div>");
         
         html.AppendLine ("</body>");
         html.AppendLine ("</html>");
         
         return html.ToString ();
      }
      
      /// <summary>
      /// Builds the main content title data.
      /// </summary>
      /// <returns>Main content title html string.</returns>
      private string BuildMainContentTitle ()
      {
         return string.Format ("{0} {1}{2}", this.m_CurrentLink.HasBook ? this.Book.Name : this.m_CurrentLink.FullLink,
                               this.m_CurrentLink.HasSubBook ? this.m_CurrentLink.SubBook : string.Empty,
                               this.m_CurrentLink.HasChapter ? " " + this.m_CurrentLink.Chapter : string.Empty);
      }
      
      /// <summary>
      /// Builds the main content data.
      /// </summary>
      /// <returns>Main content html string.</returns>
      private string BuildMainContent ()
      {
         var html = new StringBuilder ();
         if (this.m_CurrentLink.IsAbout)
            html.Append (this.BookInfo.Info.Replace ("__ABOUT__", this.Book.About));
         else
         {
            html.Append ("<table width=\"100%\" class=\"table table-striped\">");
            foreach (var excerpt in this.Excerpts)
            {
               if (!string.IsNullOrEmpty (excerpt.Header))
               {
                  html.Append ("<tr>");
                  html.Append ("<td>&nbsp;</td><td>");
                  html.Append (excerpt.Header);
                  html.Append ("</td><td>&nbsp;</td>");
                  html.Append ("</tr>");
               }
               
               html.Append ("<tr>");
               html.Append ("<td valign=\"top\" align=\"right\">");
               html.Append (excerpt.Verse.ToString (CultureInfo.InvariantCulture));
               html.Append ("</td>");
               html.Append ("<td>");
               html.Append (excerpt.Passage);
               html.Append ("</td>");
               html.Append ("<td valign=\"top\" align=\"left\">");
               html.Append (excerpt.Verse.ToString (CultureInfo.InvariantCulture));
               html.Append ("</td>");
               html.Append ("</tr>");
               
               if (!string.IsNullOrEmpty (excerpt.Footer))
               {
                  html.Append ("<tr>");
                  html.Append ("<td>&nbsp;</td><td>");
                  html.Append (excerpt.Footer);
                  html.Append ("</td><td>&nbsp;</td>");
                  html.Append ("</tr>");
               }
            }
            html.Append ("</table>");
         }
         
         return html.ToString ();
      }
      
      /// <summary>
      /// Opens the given link.
      /// </summary>
      /// <param name="linkToOpen">Link to data to open.</param>
      public void Open (string linkToOpen)
      {
         var link = new Link (linkToOpen);
         
         if (!link.HasBook && !link.IsAbout)
         {
            if (linkToOpen == "Read")
            {
               if (this.Excerpts.Count == 0)
               {
                  Sqlite.Read (this.Book.FullPath, this.Excerpts, "ORDER BY Verse");
               }
            }
            else
            {
               this.Main.ShowDefinition (link.FullLink);
               return;
            }
         }
         else if (!link.IsAbout)
         {
            if (!link.Book.Equals (this.Book.Name, StringComparison.CurrentCultureIgnoreCase))
            {
               var book = this.Options.Books.First (b => b.Name.Equals (link.Book, StringComparison.CurrentCultureIgnoreCase));
               this.DockGroup.Items.Add (new ReaderViewModel (book, linkToOpen));
               return;
            }
            string filter = link.HasSubBook
               ? string.Format ("WHERE Book='{0}' AND Chapter='{1}'", link.SubBook, link.Chapter)
               : string.Format ("WHERE Chapter='{0}'", link.Chapter);
            this.Excerpts.Clear ();
            Sqlite.Read (this.Book.FullPath, this.Excerpts, filter + " ORDER BY Verse");
         }
         this.m_CurrentLink = link;
         string mainContent;
         string mainContentTitle;
         var html = this.BuildHtml (out mainContent, out mainContentTitle);
         if (string.IsNullOrEmpty (this.Html))
            this.Html = html;
         else
            this.m_Html = html;
         if (this.HtmlChangeRequested != null)
         {
            this.HtmlChangeRequested (new HtmlChangeEventArgs
                                      {
                                         TagId = "mainContent",
                                         Change = "html",
                                         Content = mainContent
                                      });
            this.HtmlChangeRequested (new HtmlChangeEventArgs
                                      {
                                         TagId = "mainContentTitle",
                                         Change = "html",
                                         Content = mainContentTitle
                                      });
         }
      }
      
      /// <summary>
      /// Occurs when the tab is closing.
      /// </summary>
      /// <returns>True if ok to close, otherwise false.</returns>
      public override bool Closing ()
      {
         if (this.ItemClosing != null)
            this.ItemClosing (this, EventArgs.Empty);
         return true;
      }
      
      #endregion
   }
}
